package com.csj.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import reactor.core.publisher.Mono;

/**
 * spring cloud gateway作为spring cloud的第二代网关，功能比zuul更加强大。
 * 网关作为一个系统的流量的入口，有着举足轻重的作用：
 * 协议转换，路由转发
 * 流量聚合，对流量进行监控，日志输出
 * 作为整个系统的前端工程，对流量进行控制，有限流的作用
 * 作为系统的前端边界，外部流量只能通过网关才能访问系统
 * 可以在网关层做权限的判断
 * 可以在网关层做缓存
 * */
@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    /**
     * 在下面的myRoutes方法中，使用了一个RouteLocatorBuilder的bean去创建路由，
     * 除了创建路由RouteLocatorBuilder可以让你添加各种predicates和filters，
     * predicates断言的意思，顾名思义就是根据具体的请求的规则，由具体的route去处理，
     * filters是各种过滤器，用来对请求做各种判断和修改。
     *
     * 我们使用了另外一个router，该router使用host去断言请求是否进入该路由，当请求的host有“*.hystrix.com”，
     * 都会进入该router，该router中有一个hystrix的filter,该filter可以配置名称、和指向性fallback的逻辑的地址，比如本案例中重定向到了“/fallback”。
     * */
    @Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
        //可见当我们向gateway工程请求“/get”,gateway会将工程的请求转发到“http://httpbin.org/get”，
        // 并且在转发之前，加上一个filter，该filter会将请求添加一个header,key为Hello，value为World。
        String httpUri = "http://httpbin.org:80";
        return builder.routes()
                .route(p -> p
                        .path("/get")
                        .filters(f -> f.addRequestHeader("Hello", "World"))
                        .uri(httpUri))
                .route(p -> p
                        .host("*.hystrix.com")
                        .filters(f -> f.hystrix(config -> config
                                        .setName("mycmd")
                                        .setFallbackUri("forward:/fallback")))
                        .uri(httpUri))
                .build();
    }

    @RequestMapping("/fallback")
    public Mono<String> fallback() {
        return Mono.just("fallback");
    }
}
